﻿using System;
using System.Collections.Generic;
using System.Text;
using FlickrXplorer.Web;
using FlickrXplorer.Web.Controllers;
using FlickrXplorer.Web.Models;
using FlickrXplorer.Web.ViewData;
using FlickrXplorer.Web.Utilities;
using FlickrXplorer.Web.ViewData;
using NUnit.Framework;
using FlickrXplorer.Test.Helpers;
using System.Web.Routing;
using Rhino.Mocks;
using System.Web.Mvc;
using System.Reflection;


namespace FlickrXplorer.Test.Controllers
{
    [TestFixture]
    public class PhotoControllerTest
    {
        private PhotoCollection GetDummyPhotoData(int total, int perPage)
        {
            PhotoCollection photos = new PhotoCollection();

            photos.Page = 1;
            photos.Pages = total / perPage + ((total % perPage) > 0 ? 1 : 0);

            photos.Total = total;

            for (int index = 0; index < total; index++)
            {
                photos.Add(new Photo { Id = index.ToString(), Title = "Dummy " + index.ToString(), Url = Guid.NewGuid().ToString() });
            }

            return photos;
        }
        [Test]
        public void Index()
        {
            MockRepository repository = new MockRepository();

            IPhotoModel model = repository.DynamicMock<IPhotoModel>();
            SetupResult.For(model.GetInterestingPhotos("City", 0, 12)).Return(GetDummyPhotoData(20, 12));
            repository.Replay(model);

            ISecurityModel securityModel = repository.DynamicMock<ISecurityModel>();
            SetupResult.For(securityModel.GetAuthenticatedUser()).Return(new People
                                                                         {
                                                                             Id = "1",
                                                                             IsPro = false,
                                                                             Location = "Sofia",
                                                                             IconUrl = string.Empty,
                                                                             RealName = "Mehfuz",
                                                                             Username = "mehfuz"
                                                                         });


            repository.Replay(securityModel);

            const string url = "~/flickrMvc.net/";

            PhotoController pController = null;

            FakeContext(repository, model, securityModel,  url, ref pController);

            var result = pController.Index("City", 1, null) as ViewResult;

            PhotoData photoData = result.ViewData.Model as PhotoData;

            Assert.IsTrue(photoData.Photos.Count == 20);
            Assert.IsTrue(photoData.Photos.Page == 1 && photoData.Photos.Pages == 2);
        }

        private void FakeContext(MockRepository repository, IPhotoModel model, ISecurityModel securityModel, string url, ref PhotoController controller)
        {
            controller = new PhotoController(model, securityModel);

            var httpContext = repository.FakeHttpContext(url);
            ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller);
            controller.ControllerContext = context;
        }

        private PhotoDetail GetPhotoDetail()
        {
            PhotoDetail detail = new PhotoDetail();

            detail.Id = "1";
            detail.Title = "Calsburg";
            detail.Username = "1x";
            detail.Tags = new string[] { "hill", "mountain", "california", "redmond"};
            detail.Description = "This is dummy detail photo";
            detail.Url = string.Empty;

            IList<PhotoComment> comments = new List<PhotoComment>();
            
            comments.Add(new PhotoComment
            {
                Author = "mehfuz",
                PermaLink = "#",
                PhotoId = "1",
                AuthorName = "Mehfuz Hossain",
                Text = "What a nice photo!"
            });
     
            return detail;

        }

        [Test]
        public void Detail()
        {
            MockRepository repository = new MockRepository();
           
            IPhotoModel model = repository.DynamicMock<IPhotoModel>();

            PhotoDetail detail = GetPhotoDetail();

            SetupResult.For(model.GetPhoto("1")).Return(detail);
            repository.Replay(model);
                
            PhotoController pController = null;

            FakeContext(repository, model, null, "~/flickrMvc.net/Detail/1", ref pController);

            var result = pController.Detail("1") as ViewResult;

            PhotoDetail viewDetail = result.ViewData.Model as PhotoDetail;
            //right photo in the view.
            Assert.AreEqual(detail.Id, viewDetail.Id);
            //Assert.AreEqual(detail.Comments.Count, viewDetail.Comments.Count);
            Assert.AreEqual(detail.Tags.Length, viewDetail.Tags.Length);
            Assert.AreEqual(detail.Username, viewDetail.Username);
            //Assert.AreEqual("Detail", result.ViewName, "Method not called");
        }

        [Test]
        public void User()
        {
            MockRepository repository = new MockRepository();
            IPhotoModel model = repository.DynamicMock<IPhotoModel>();
            ISecurityModel secModel = repository.DynamicMock<ISecurityModel>();


            PhotoController pController = null;

            // no photo user found stage.
            SetupResult.For(model.GetPeople("don box")).Return(null);
            // replay
            repository.Replay(model);

            SetupResult.For(secModel.GetAuthenticatedUser()).Return(new People());

            repository.Replay(secModel);
            
            FakeContext(repository, model, secModel, "~/flickrMvc.net/User/don+box", ref pController);

            var result = pController.User("don+box", string.Empty, null, null) as ViewResult;

            PhotoData photoData = result.ViewData.Model as PhotoData;

            Assert.IsTrue(result.ViewData["UserObject"] != null);
            // no user found.
            Assert.IsTrue(photoData.Photos.Count == 0);
        }

        [Test]
        public void Controller_To_RoutingTable()
        {
            var app = new GlobalApplication();
            
            RouteCollection routes = new RouteCollection();
            
            app.RegisterRoutes(routes);

            MockRepository mocks = new MockRepository();
            
            Type controllerType = typeof(PhotoController);
            MethodInfo[] infos = controllerType.GetMethods();

            foreach (MethodInfo info in infos)
            {
                object[] attributes = info.GetCustomAttributes(typeof(MvcActionAttribute), false);
                // mvc routines.
                if (attributes.Length == 1)
                {
                    StringBuilder builder = new StringBuilder();

                    builder.Append("~/Photo/");
                    builder.Append(info.Name + "/");

                    ParameterInfo[] parameters = info.GetParameters();

                    bool firstParam = true;

                    foreach (ParameterInfo param in parameters)
                    {
                        if (!param.IsOptional)
                        {
                            if (firstParam)
                            {
                                builder.Append("?" + param.Name + "=" + param.Position);
                                firstParam = false;
                            }
                            else
                                builder.Append("&" + param.Name + "=" + param.Position);
                        }
                    }

                    string url = builder.ToString();

                    TestUrlCatch(mocks, routes, url);
                }
            }
        }

        private static void TestUrlCatch(MockRepository mocks, RouteCollection routes, string url)
        {
            var context = mocks.FakeHttpContext(url);

            var data = routes.GetRouteData(context);
            Assert.IsTrue(data != null, "Failed For:" + url);
            
            string controller_action = data.Values["controller"] + "-" + data.Values["action"];
            Console.Out.WriteLine(controller_action);
        }
    }
}
